/**
 *   Copyright 2014 Royce Remulla
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package cjcast.y2008.problem;

import cjcast.y2008.problem.AlwaysTurnLeftHelper.Direction;


/**
 * Helper class for AlwaysTurnLeft.
 * 
 * <pre>
 * $Author: royce.com@gmail.com $ 
 * $Date: 2014-02-14 06:09:35 +0000 (Fri, 14 Feb 2014) $
 * </pre>
 * 
 * @author r39
 */

public class AlwaysTurnLeftHelper {

    /** */
    enum Move {

        /** */
        Left('L'), Right('R'), Walk('W');

        /** */
        private final char value;

        Move(final char pValue) {
            this.value = pValue;
        }

        /**
         * @return the value
         */
        public char getValue()
        {
            return this.value;
        }

        /**
         * @param move
         * @return
         */
        public static Move fromChar(final char move)
        {
            Move retval = null; //NOPMD: null default, conditionally redefine.
            for (final Move nextMove : values()) {
                if (nextMove.value == move) {
                    retval = nextMove;
                    break;
                }
            }
            assert retval != null;
            return retval;
        }

    }

    /** */
    enum Direction {
        /** */
        NORTH(0x1), WEST(0x4), SOUTH(0x2), EAST(0x8);

        /** Can walk on this direction bit flag. */
        private final transient int bit;

        Direction(final int pBit) {
            this.bit = pBit;
        }

        /**
         * @return the bit
         */
        public int getBit()
        {
            return this.bit;
        }

        Direction turn(final char leftOrRight)
        {
            assert leftOrRight == 'L' || leftOrRight == 'R' : "Invalid turn!";

            final Move move = Move.fromChar(leftOrRight);
            assert move != null;
            int currentIdx;
            if (move == Move.Left) {
                currentIdx = (values().length + this.ordinal() - 1)
                        % values().length;
            } else if (move == Move.Right) {
                currentIdx = (this.ordinal() + 1) % values().length;
            } else {
                currentIdx = -1;
            }
            return values()[currentIdx];
        }
    }


}

/** Represents a spot in the maze. */
class MazeRoom {

    /** Room type. */
    static final char[] TYPE = "0123456789ABCDEF".toCharArray();

    /** Relative column index of this room. */
    private final transient int column;


    /** Actual row index of this room. */
    private final transient int row;

    /** Room type. */
    private transient int type;

    /**
     * @param pColumn
     * @param pRow
     */
    protected MazeRoom(final int pColumn, final int pRow) {
        super();
        this.column = pColumn;
        this.row = pRow;
    }

    int getColumn()
    {
        return this.column;
    }


    int getRow()
    {
        return this.row;
    }


    /**
     * @return
     */
    public char getType()
    {

        return TYPE[this.type];
    }

    void setCanWalk(final Direction direction)
    {
        this.type |= direction.getBit();
    }

    /**
     * @see {@link Object#toString()}
     * @return String representation of this instance.
     */
    public String toString()
    {
        final StringBuilder strBuilder = new StringBuilder();
        strBuilder.append("Room(" + getColumn() + ", " + getRow() + "): "
                + getType());
        return strBuilder.toString();

    }

}
